#ifndef IGSLIB_IGPIO_H
#define IGSLIB_IGPIO_H

#include <igslib_common_use.h>
#include <igslib_iserial_manager.h>


namespace igslib
{
    struct IGPIOEvent;
    /*!
     * GPIO: General Purpose Input and Output.
     * 通用型輸入輸出。
     */
	struct IGPIO:public IComponent
	{
        /*!
         * 一個GPIO通常可設定的模式。
         */
        enum class mode
        {
            input,     //!< 用於接收訊號。
            output,    //!< 用於打出訊號。
            undefined, //!< 未設定或裝置無效。
        };
        /*!
         * 一個GPIO通常可設定的狀態。
         */
        enum class state
        {
            low,        //!< 低電壓狀態。
            high,       //!< 高電壓狀態。
            undefined,  //!< 未設定或裝置無效。
        };
        /*!
         * 設定相關事件處理者。
         * @param a0 相關事件處理者。
         */
        virtual void SetEventHandler(IGPIOEvent*)=0;
        /*!
         * 設定為輸入或輸出模式。
         * @param a0 設定值。
         * @return
         *     0: 操作正常。
         *     -1: 操作失敗。
         */
        virtual int SetMode(const mode&)=0;
        /*!
         * 取得目前被設定的模式。
         * @return 被設定的模式。
         */
        virtual mode GetMode()=0;
        /*!
         * 對output pin設定狀態。
         * @note 若裝置支援對input設定狀態，亦於此介面實作。
         * @return
         *     0: 操作正常。
         *     -1: 操作失敗。
         */
        virtual int SetState(const state&)=0;
        /*!
         * 讀取input pin狀態。
         * @return true表示為high，false表示為low。
         * @note 若裝置支援對output讀取狀態，亦於此介面實作。
         */
        virtual state GetState()=0;
        /*!
         * 取得針腳名。
         * @return 針腳名。
         */
        virtual std::string GetPinName()=0;
        /*!
         * 取得標籤名。
         * @return 標籤名。
         */
        virtual std::string GetName()=0;
        /*!
         * 更新裝置狀態。
         */
        virtual void Update()=0;
        /*!
         * 取得此pin腳在板底上制定的號碼。
         * @return 此pin腳在板底上制定的號碼。
         * @note
         *     若用戶看到的GPIO是金手指的話，此函式傳回的就是HardwareMap上制定金手指的號碼。
         */
        virtual int GetNumber()=0;
        /*!
         * 設定此pin腳在板底上制定的號碼。
         * @param a0 此pin腳在板底上制定的號碼。
         * @return
         *     0: 操作正常。
         *     -1: 號碼錯誤。
         * @note
         *     若用戶看到的GPIO是金手指的話，此函式傳回的就是HardwareMap上制定金手指的號碼。
         */
        virtual int SetNumber(const int&)=0;
        /*!
         * 若實作是使用SPI通訊介面，用此函式輸入SPI的實作。
         * @param a0 SPI的實作。
         */
        virtual void SetSPI(ISpi*)=0;
	};
    struct IGPIOEvent
    {
        /*!
         * 當狀態發生變化時觸發。
         * @param a0 事件容器(擁有者)。
         * @param a1 舊值。
         * @param a2 新值。
         */
        virtual void OnChangeState(IGPIO*,const IGPIO::state&,const IGPIO::state&)=0;
        /*!
         * 當模式發生變化時觸發。
         * @param a0 事件容器(擁有者)。
         * @param a1 舊值。
         * @param a2 新值。
         */
        virtual void OnChangeMode(IGPIO*,const IGPIO::mode&,const IGPIO::mode&)=0;
    };

    struct IGPIOManager:public IManager<IGPIO*>
    {
        /*!
         * 創建一個適用於M01的GPIO裝置。
         * @param a0 pin腳編號。
         * @return 創建出來的GPIO裝置。
         *     nullptr：創建失敗。
         *     other：實作指標。
         */
        virtual IGPIO* NewM01GPIO(const int&)=0;
		/*!
         * 創建MH主板上根據專案特規實作MCU資源。
         * @param a0 專案名。
         * @return 根據專案特規實作MCU資源。
         *     nullptr：創建失敗。
         *     other：實作指標。
         * @note
         *     目前已實作專案名對照如下：
         *     "DragonBallRace"：龍珠賽球
         *     "DragonWarrior"：鬥龍戰士
         *     "M01_TestPattern" : m01底版 
         */
        virtual IGPIO* New_ProjMCU(const std::string&)=0;
    };
};
extern "C"{
    igslib::IGPIOManager* GetGPIOManagerInstance();
};

#endif
